/*
 * i2c_peripherals.c
 *
 *  Created on: 21.03.2012
 *      Author: Roman Leitner
 */

#include "LPC13xx.h"			/* LPC134x Peripheral Registers */


#include "../config/type.h"
#include "../driver/i2c.h"
#include "i2c_peripherals.h"
#include "misc.h"

extern volatile uint8_t I2CMasterBuffer[BUFSIZE];
extern volatile uint8_t I2CSlaveBuffer[BUFSIZE];
extern volatile uint32_t I2CMasterState;
extern volatile uint32_t I2CReadLength, I2CWriteLength;

static bool _DS1307Initialised = false;
static bool _TSL2550Initialised = false;

int I2C_delay = 200;

/**************************************************************************/
/*!
	 Reads x bytes into a buffer
*/
/**************************************************************************/
i2c_Error_t I2C_ReadBuffer(uint8_t address, uint8_t reg, uint8_t *buffer, uint32_t len)
{
  if (len > BUFSIZE)
    return I2C_ERROR_I2C_BUFFEROVERFLOW;

  // Clear write buffers
  uint32_t i;
  for ( i = 0; i < BUFSIZE; i++ )
  {
    I2CMasterBuffer[i] = 0x00;
  }

  I2CWriteLength = 2;
  I2CReadLength = len;
  I2CMasterBuffer[0] = address;
  I2CMasterBuffer[1] = reg;                       // Command register
  I2CMasterBuffer[2] = address | RD_BIT;
  I2CEngine();

  // Push response into buffer
  for ( i = 0; i < len; i++ )
  {
    buffer[i] = I2CSlaveBuffer[i];
  }
  for ( i = 0; i < I2C_delay; i++ );	/* Delay after write */

  return I2C_ERROR_OK;
}
i2c_Error_t I2C_Receive_Byte(uint8_t address, uint8_t *buffer)
{
   // Clear write buffers
  uint32_t i;
  for ( i = 0; i < BUFSIZE; i++ )
  {
    I2CMasterBuffer[i] = 0x00;
    I2CSlaveBuffer[i]  = 0x00;
  }

  I2CWriteLength = 0;
  I2CReadLength = 1;
  I2CMasterBuffer[0] = address | RD_BIT;
  I2CEngine();

    *buffer =  I2CSlaveBuffer[0];

    for ( i = 0; i < I2C_delay; i++ );	/* Delay after write */

  return I2C_ERROR_OK;
}
/**************************************************************************/
/*!
    Send an 8 bit value to Slave
*/
/**************************************************************************/
i2c_Error_t I2C_Write8 (uint8_t address, uint8_t reg, uint32_t value)
{
  // Clear write buffers
  uint32_t i;
  for ( i = 0; i < BUFSIZE; i++ )
  {
    I2CMasterBuffer[i] = 0x00;
  }

  I2CWriteLength = 3;
  I2CReadLength = 0;
  I2CMasterBuffer[0] = address;
  I2CMasterBuffer[1] = reg;                       // Command register
  I2CMasterBuffer[2] = (value & 0xFF);            // Value to write
  I2CEngine();
  for ( i = 0; i < I2C_delay; i++ );	/* Delay after write */

  return I2C_ERROR_OK;
}
i2c_Error_t I2C_Send_Byte (uint8_t address, uint32_t value)
{
  // Clear write buffers
  uint32_t i;
  for ( i = 0; i < BUFSIZE; i++ )
  {
    I2CMasterBuffer[i] = 0x00;
  }

  I2CWriteLength = 1;
  I2CReadLength = 0;
  I2CMasterBuffer[0] = address;
  I2CMasterBuffer[1] = (value & 0xFF);            // Value to write
  I2CEngine();
  for ( i = 0; i < I2C_delay; i++ );	/* Delay after write */
  return I2C_ERROR_OK;
}

/**************************************************************************/
/*!
    Initialises the I2C block for DS1307
*/
/**************************************************************************/
DS1307Error_t DS1307Init(void)
{
	DS1307Error_t error = DS1307_ERROR_OK;

	uint8_t buffer[1];
	// read current Second value
	error = I2C_ReadBuffer(DS1307_RTC_ADDRESS, DS1307_REG_RTC_SECOND, buffer, sizeof(buffer));

	buffer[1] &= 0x7F; // mask CH bit to start clock.

    error = I2C_Write8(DS1307_RTC_ADDRESS, DS1307_REG_RTC_SECOND, buffer[1]);

    error = I2C_ReadBuffer(DS1307_RTC_ADDRESS, DS1307_REG_RTC_SECOND, buffer, sizeof(buffer));

    buffer[1] = 0x00;
    error = I2C_Write8(DS1307_RTC_ADDRESS, DS1307_REG_RTC_CONTROL, buffer[1]);


    _DS1307Initialised = true;

  return error;
}


/**************************************************************************/
/*!
    Sets the current date/time from the RTC
*/
/**************************************************************************/
DS1307Error_t DS1307SetTime(uint8_t control, uint8_t dayofweek, uint8_t day, uint8_t month, uint8_t year, uint8_t hour, uint8_t minute, uint8_t second)
{
  DS1307Error_t error = DS1307_ERROR_OK;

  if (!_DS1307Initialised)
  {
    error = DS1307Init();
    if (error) return error;
  }

  error = I2C_Write8(DS1307_RTC_ADDRESS, DS1307_REG_RTC_SECOND, DecToBCD(second & 0x7F));
  if (error) return error;
  error = I2C_Write8(DS1307_RTC_ADDRESS, DS1307_REG_RTC_MINUTE, DecToBCD(minute & 0x7F));
  if (error) return error;

  error = I2C_Write8(DS1307_RTC_ADDRESS, DS1307_REG_RTC_HOUR, DecToBCD(( (hour & 0x3F) | DS1307_HR_MILITARY)));
  if (error) return error;
  error = I2C_Write8(DS1307_RTC_ADDRESS, DS1307_REG_RTC_DATE, DecToBCD(day & 0x3F));
  if (error) return error;
  error = I2C_Write8(DS1307_RTC_ADDRESS, DS1307_REG_RTC_MONTH, DecToBCD(month & 0x1F));
  if (error) return error;
  error = I2C_Write8(DS1307_RTC_ADDRESS, DS1307_REG_RTC_YEAR, DecToBCD(year));
  if (error) return error;
  error = I2C_Write8(DS1307_RTC_ADDRESS, DS1307_REG_RTC_DAYOFWEEK, DecToBCD(dayofweek & 0x07));
  if (error) return error;
  error = I2C_Write8(DS1307_RTC_ADDRESS, DS1307_REG_RTC_CONTROL, control );
  if (error) return error;

  return error;
}

/**************************************************************************/
/*!
    Reads the current date/time from the RTC
*/
/**************************************************************************/
DS1307Error_t DS1307GetTime(RTC_time_t *time)
{
  DS1307Error_t error = DS1307_ERROR_OK;
  uint8_t buffer[8];

  if (!_DS1307Initialised)
  {
    error = DS1307Init();
    if (error) return error;
  }

  // Read 7 bytes at once into buffer
  error = I2C_ReadBuffer(DS1307_RTC_ADDRESS,
		  	  	  	  	   DS1307_REG_RTC_SECOND,
                           buffer, sizeof(buffer));

  if (!error)
  {
    time->second = BCDToDec(buffer[0] & 0xFF);
    time->minute = BCDToDec(buffer[1] & 0x7F);
    time->hour = BCDToDec(buffer[2] & 0x3F); // 0x3F;
    time->dayofweek = buffer[3] & 0x07;
    time->day = BCDToDec(buffer[4] & 0x3F);
    time->month = BCDToDec(buffer[5] & 0x1F);
    time->year = BCDToDec(buffer[6]);
    time->status = buffer[7];
  }

  return error;
}

// Lookup table for channel ratio (i.e. channel1 / channel0)
unsigned char ratioLut[129] = {
100,100,100,100,100,100,100,100,
100,100,100,100,100,100,99,99,
99,99,99,99,99,99,99,99,
99,99,99,98,98,98,98,98,
98,98,97,97,97,97,97,96,
96,96,96,95,95,95,94,94,
93,93,93,92,92,91,91,90,
89,89,88,87,87,86,85,84,
83,82,81,80,79,78,77,75,
74,73,71,69,68,66,64,62,
60,58,56,54,52,49,47,44,
42,41,40,40,39,39,38,38,
37,37,37,36,36,36,35,35,
35,35,34,34,34,34,33,33,
33,33,32,32,32,32,32,31,
31,31,31,31,30,30,30,30,
30
};

// Lookup table to convert channel values to counts
unsigned short countLut[128] = {
   0,   1,   2,   3,   4,   5,   6,   7,
   8,   9,  10,  11,  12,  13,  14,  15,
  16,  18,  20,  22,  24,  26,  28,  30,
  32,  34,  36,  38,  40,  42,  44,  46,
  49,  53,  57,  61,  65,  69,  73,  77,
  81,  85,  89,  93,  97, 101, 105, 109,
 115, 123, 131, 139, 147, 155, 163, 171,
 179, 187, 195, 203, 211, 219, 227, 235,
 247, 263, 279, 295, 311, 327, 343, 359,
 375, 391, 407, 423, 439, 455, 471, 487,
 511, 543, 575, 607, 639, 671, 703, 735,
 767, 799, 831, 863, 895, 927, 959, 991,
1039,1103,1167,1231,1295,1359,1423,1487,
1551,1615,1679,1743,1807,1871,1935,1999,
2095,2223,2351,2479,2607,2735,2863,2991,
3119,3247,3375,3503,3631,3759,3887,4015
};
const kMaxLux = 1846;   // standard mode max


/*****************************************************************************
** Function name:		TSL2550_init
**
** Descriptions:		Initial Sequence for TSL2550 LightSensor
**
** parameters:			None
** Returned value:		CMDReg value
**
*****************************************************************************/
TSL2550Error_t TSL2550_init( void )
{
	TSL2550Error_t error = TSL2550_ERROR_OK;

	uint8_t buffer;
	// disable device
	error = I2C_Send_Byte(TSL2550_LIGHT_ADDRESS, TSL2550_LIGHT_CMD_POWER_DOWN);
	error = I2C_Receive_Byte(TSL2550_LIGHT_ADDRESS, &buffer);

	// wake up device
		error = I2C_Send_Byte(TSL2550_LIGHT_ADDRESS, TSL2550_LIGHT_CMD_POWER_UP);
		error = I2C_Receive_Byte(TSL2550_LIGHT_ADDRESS, &buffer);

	if (buffer != TSL2550_LIGHT_CMD_POWER_UP)
		return TSL2550_ERROR_READVALUE_NOTCORRECT;

	// set standart range mode
	error = I2C_Send_Byte(TSL2550_LIGHT_ADDRESS, TSL2550_LIGHT_CMD_STANDARD_RANGE);
	error = I2C_Receive_Byte(TSL2550_LIGHT_ADDRESS, &buffer);
	if ((buffer & 0xFC) != TSL2550_LIGHT_CMD_STANDARD_RANGE)  // mask the 0x03 powerup status
		return TSL2550_ERROR_READVALUE_NOTCORRECT;
	else
	{
		_TSL2550Initialised = true;
	  return TSL2550_ERROR_OK;
	}
}

TSL2550Error_t TSL2550GetLum(uint8_t *broad, uint8_t *ir)
{
	TSL2550Error_t error = TSL2550_ERROR_OK;

	error = I2C_Send_Byte(TSL2550_LIGHT_ADDRESS, TSL2550_LIGHT_CMD_READ_ADC0);
	if (error) return error;
	error = I2C_Receive_Byte(TSL2550_LIGHT_ADDRESS, broad);
	if (error) return error;

	error = I2C_Send_Byte(TSL2550_LIGHT_ADDRESS, TSL2550_LIGHT_CMD_READ_ADC1);
	if (error) return error;
	error = I2C_Receive_Byte(TSL2550_LIGHT_ADDRESS, ir);
	if (error) return error;

	if ((*broad & 0x80) != 0x80)
		return TSL2550_ERROR_BROADBAND_INVALID;

	if ((*ir & 0x80) != 0x80)
		return TSL2550_ERROR_IR_INVALID;
	*broad &= 0x7f;
	*ir &= 0x7f;

	return TSL2550_ERROR_OK;
}

/**************************************************************************/
/*!
	 Gets new sensor values and calculates Lux
*/
/**************************************************************************/
uint32_t TSL2550GetLux()
{
	uint32_t lux;
	uint8_t broadband, ir;

	TSL2550Error_t error = TSL2550_ERROR_OK;

	error = TSL2550GetLum(&broadband, &ir);
	if (error == TSL2550_ERROR_OK)
	{
	 lux = TSL2550CalcLux(broadband , ir );  // mask valid bit
		return lux;
	}
	else
	{
		return 0;
	}
}

/**************************************************************************/
/*!
	 Calulate LUX new values out of sensor values.
*/
/**************************************************************************/
uint32_t TSL2550CalcLux(uint8_t broadband, uint8_t ir)
{
	uint32_t lux;

	unsigned short count_br = countLut[broadband];
	unsigned short count_ir = countLut[ir];

	// calculate ratio
	// Note: the "128" is a scaling factor
	unsigned char ratio = 128;    // default
	// avoid division by zero
	// and count_ir cannot be greater than count_br
	if ((count_br) && (count_ir <= count_br))
	      ratio = (count_br * 128 / count_br);

	// calculate lux
	// Note: the "256" is a scaling factor
	 lux = ((count_br - count_ir) * ratioLut[ratio]) / 256;
	// range check lux
	if (lux > kMaxLux) lux = kMaxLux;

	return lux;
}



